package com.huwei.util;

import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;

import lombok.extern.slf4j.Slf4j;


/**
 * bean util
 * @author huwei
 */
@Slf4j
public class BeanUtil {
	
	static private Gson gson = new GsonBuilder().disableHtmlEscaping().create(); 
	
	static public Map<String ,Object> toMap(Object obj){
		return toMap(obj, null);
	}
	
	static public Map<String ,Object> toMap(String key ,Object obj){
		Map<String ,Object> empty = new HashMap<String, Object>();
		empty.put(key, obj);
		return empty;
	}
	
	static public Map<String ,Object> toMap(Object obj ,String ...excludeFields){
		Map<String ,Object> empty = new HashMap<String, Object>();
		
		if(Objects.isNull(obj)) {
			return empty;
		}
		
		return beanToMap(obj ,excludeFields);
	}
	
	/**
	 *  将 target目标的feild属性值赋值给original对象；
	 * @param original
	 * @param target
	 * @return
	 */
	static public <T> T addFeildValueInOrginal(T original ,T target) {
		if(Objects.isNull(original) || Objects.isNull(target) || !original.getClass().equals(target.getClass())) {
			return original;
		}
		
		return addFeildValueInOrginal0(original, target);
	}
	
	/**
	 * 将给定的对象转换为json字符串，转换失败返回null
	 * @param obj
	 * @return
	 */
	static public String toJson(Object obj) {
		try {
			return gson.toJson(obj);
		} catch (Exception e) {
			log.warn("---- > switch object to json string is failed ,and that object is : " + obj.toString() ,e);
		}
		return  null;
	}
	
	/**
	 * 将给定的json字符串转换为给定的class对象，失败返回null
	 * @param json
	 * @param cls
	 * @return
	 */
	static public <T> T toBean(String json ,Class<? extends T> cls) {
		try {
			return gson.fromJson(json, cls);
		} catch (Exception e) {
			log.warn("---- > switch json string to bean is failed ,and that object class is : " + cls + " ,and that json string is : " + json,e);
		}
		return null;
	}
	
	static public <T> T toBean(byte[] json ,Class<? extends T> cls) {
		return toBean(new String(json), cls);
	}
	
	static public <T> T toBean(byte[] json ,Charset charset ,Class<? extends T> cls) {
		try {
			return toBean(new String(json ,charset.name()), cls);
		} catch (UnsupportedEncodingException e) {
			log.warn("---- > switch json string to bean is failed ,and that object class is : " + cls + " ,and that json string is : " + json
					+ " ;cause is is no given character : " + charset,e);
			return null;
		}
	}

	static private <T> T addFeildValueInOrginal0(T original, T target) {
		Field[] originalFields = getDeclaredFields(original);
		Map<String ,Object> targetFields = beanToMap(target, null);
		
		if(Objects.isNull(originalFields)) {
			return original;
		}
		
		for(int i = 0 ,len = originalFields.length ;i < len ;++i) {
			Field f = originalFields[i];
			f.setAccessible(true);
			Object originalValue = null;
			try {
				originalValue = f.get(original);
			} catch (IllegalArgumentException e) {
			} catch (IllegalAccessException e) {
			}
			
			if(!Objects.isNull(originalValue)) {
				continue;
			}
			
			String name = f.getName();
			try {
				f.set(original, targetFields.get(name));
			} catch (IllegalArgumentException | IllegalAccessException e) {
				// 
			}
		}
		return original;
	}

	private static Field[] getDeclaredFields(Object original) {
		return original.getClass().getDeclaredFields();
	}

	private static Map<String, Object> beanToMap(Object obj, String[] excludeFields) {
		Map<String ,Object> result = new HashMap<String, Object>();
		
		Class<?> cls = obj.getClass();
		Field[] fields = cls.getDeclaredFields();
		
		if(Objects.isNull(fields) || fields.length == 0) {
			return result;
		}
		
		for(int i = 0 ,len = fields.length ;i < len ;++i) {
			Field field = fields[i];
			//打开私有访问
            field.setAccessible(true);
            //获取属性
            String name = field.getName();
            
            //排除属性
            if(valueInArrays(name ,excludeFields)) {
            	continue;
            }
            //获取属性值
            Object value = null;
            try {
				value = field.get(obj);
			} catch (IllegalArgumentException e) {
			} catch (IllegalAccessException e) {
			}
            
            result.put(name, value);
		}
		return result;
	}

	private static boolean valueInArrays(String name, String[] excludeFields) {
		if(Objects.isNull(name) || Objects.isNull(excludeFields) || excludeFields.length == 0) {
			return false;
		}
		
		for(int i = 0 ,len = excludeFields.length ;i < len ;++i) {
			if(name.equals(excludeFields[i])) {
				return true;
			}
		}
		
		return false;
	}

	public static byte[] toJsonAsBytes(Object obj) {
		String json = toJson(obj);
		return Objects.isNull(json) ? new byte[0] : json.getBytes();
	}
	
}
